///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef __Controller_H__
#define __Controller_H__

#include "OgrePrerequisites.h"

#include "OgreSharedPtr.h"

namespace Ogre {

	
	
	
	
	
	template <typename T>
	class ControllerFunction : public MemAlloc_General
    {
    protected:
        /// If true, function will add input values together and wrap at 1.0 before evaluating
        bool mDeltaInput;
        T mDeltaCount;

        
        T getAdjustedInput(T input)
        {
            if (mDeltaInput)
            {
                mDeltaCount += input;
                // Wrap
                while (mDeltaCount >= 1.0)
                    mDeltaCount -= 1.0;
                while (mDeltaCount < 0.0)
                    mDeltaCount += 1.0;

                return mDeltaCount;
            }
            else
			{
                return input;
            }
        }

    public:
        
        ControllerFunction(bool deltaInput)
        {
            mDeltaInput = deltaInput;
            mDeltaCount = 0;
        }

		virtual ~ControllerFunction() {}

        virtual T calculate(T sourceValue) = 0;
    };


    
	template <typename T>
	class ControllerValue : public MemAlloc_General
    {

    public:
        virtual ~ControllerValue() { }
        virtual T getValue(void) const = 0;
        virtual void setValue(T value) = 0;

    };

    
	template <typename T>
	class Controller : public MemAlloc_General
    {
    protected:
        /// Source value
        SharedPtr< ControllerValue<T> > mSource;
        /// Destination value
        SharedPtr< ControllerValue<T> > mDest;
        /// Function
        SharedPtr< ControllerFunction<T> > mFunc;
		/// Controller is enabled or not
        bool mEnabled;


    public:

        
        Controller(const SharedPtr< ControllerValue<T> >& src, 
			const SharedPtr< ControllerValue<T> >& dest, const SharedPtr< ControllerFunction<T> >& func)
			: mSource(src), mDest(dest), mFunc(func)
		{
			mEnabled = true;
		}

        
		virtual ~Controller() {}


		/// Sets the input controller value
        void setSource(const SharedPtr< ControllerValue<T> >& src)
		{
			mSource = src;
		}
		/// Gets the input controller value
        const SharedPtr< ControllerValue<T> >& getSource(void) const
		{
			return mSource;
		}
		/// Sets the output controller value
        void setDestination(const SharedPtr< ControllerValue<T> >& dest)
		{
			mDest = dest;
		}

		/// Gets the output controller value
        const SharedPtr< ControllerValue<T> >& getDestination(void) const
		{
			return mDest;
		}

        /// Returns true if this controller is currently enabled
        bool getEnabled(void) const
		{
			return mEnabled;
		}

        /// Sets whether this controller is enabled
        void setEnabled(bool enabled)
		{
			mEnabled = enabled;
		}

        
        void setFunction(const SharedPtr< ControllerFunction<T> >& func)
		{
			mFunc = func;
		}

        
        const SharedPtr< ControllerFunction<T> >& getFunction(void) const
		{
			return mFunc;
		}

		
		void update(void)
		{
			if(mEnabled)
				mDest->setValue(mFunc->calculate(mSource->getValue()));
		}

    };

	
	

}

#endif
